// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraGameplayRpcRegistrationComponent.h"
#include "Player/LyraPlayerController.h"
#include "Character/LyraPawn.h"
#include "Player/LyraPlayerState.h"
#include "Engine/Engine.h"
#include "Engine/GameViewportClient.h"
#include "Engine/GameInstance.h"
#include "Misc/CommandLine.h"
#include "EngineMinimal.h"

#include "Character/LyraHealthComponent.h"
#include "Inventory/LyraInventoryItemDefinition.h"
#include "Inventory/LyraInventoryItemInstance.h"
#include "Inventory/LyraInventoryManagerComponent.h"
#include "Character/LyraPawnExtensionComponent.h"

ULyraGameplayRpcRegistrationComponent* ULyraGameplayRpcRegistrationComponent::ObjectInstance = nullptr; // 静态单例实例初始化

/**
 * 获取 RPC 注册组件的单例实例
 */
ULyraGameplayRpcRegistrationComponent* ULyraGameplayRpcRegistrationComponent::GetInstance()
{
#if WITH_RPC_REGISTRY
	if (ObjectInstance == nullptr) // 如果实例尚未创建
	{
		ObjectInstance = NewObject<ULyraGameplayRpcRegistrationComponent>(); // 创建新对象
		FParse::Value(FCommandLine::Get(), TEXT("externalrpclistenaddress="), ObjectInstance->ListenerAddress); // 从命令行解析监听地址
		FParse::Value(FCommandLine::Get(), TEXT("rpcsenderid="), ObjectInstance->SenderID); // 从命令行解析发送者ID
		if (!UExternalRpcRegistry::GetInstance()) // 如果外部 RPC 注册表实例不存在
		{
			GLog->Log(TEXT("BotRPC"), ELogVerbosity::Warning, FString::Printf(TEXT("无法创建 RPC 注册表实例。这可能会导致使用 RPC 注册表时出现问题。"))); // 输出警告日志
		}
		ObjectInstance->AddToRoot(); // 将对象添加到根集以防止垃圾回收
	}
#endif
	return ObjectInstance; // 返回单例实例
}

/**
 * 查找游戏世界
 */
UWorld* FindGameWorld()
{
	// 查找游戏世界
	if (GEngine->GameViewport) // 如果游戏视口存在
	{
		UGameInstance* GameInstance = GEngine->GameViewport->GetGameInstance(); // 获取游戏实例
		return GameInstance ? GameInstance->GetWorld() : nullptr; // 返回游戏实例的世界，如果不存在则返回空
	}
	return GWorld; // 返回全局世界
}

/**
 * 获取玩家控制器
 */
ALyraPlayerController* GetPlayerController()
{
	UWorld* LocalWorld = FindGameWorld(); // 查找游戏世界
	if (!LocalWorld) // 如果世界不存在
	{
		return nullptr; // 返回空
	}
	// 查找玩家控制器
	ALyraPlayerController* PlayerController = Cast<ALyraPlayerController>(LocalWorld->GetFirstPlayerController()); // 获取第一个玩家控制器并转换为 Lyra 玩家控制器
	if (!PlayerController) // 如果玩家控制器不存在
	{
		return nullptr; // 返回空
	}
	else
	{
		return PlayerController; // 返回玩家控制器
	}
}

#if WITH_RPC_REGISTRY

/**
 * 从请求体数据中解析并获取 JSON 对象
 */
TSharedPtr<FJsonObject> ULyraGameplayRpcRegistrationComponent::GetJsonObjectFromRequestBody(TArray<uint8> InRequestBody)
{
	FUTF8ToTCHAR WByteBuffer(reinterpret_cast<const ANSICHAR*>(InRequestBody.GetData()), InRequestBody.Num()); // 将 UTF-8 字节数据转换为 TCHAR
	const FString IncomingRequestBody =  FString::ConstructFromPtrSize(WByteBuffer.Get(), WByteBuffer.Length()); // 从缓冲区构造字符串
	TSharedPtr<FJsonObject> BodyObject = MakeShareable(new FJsonObject()); // 创建共享的 JSON 对象
	TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(IncomingRequestBody); // 创建 JSON 读取器

	if (FJsonSerializer::Deserialize(JsonReader, BodyObject) && BodyObject.IsValid()) // 如果反序列化成功且对象有效
	{
		return BodyObject; // 返回 JSON 对象
	}

	return nullptr; // 返回空
}

/**
 * 注册始终启用的 HTTP 回调
 */
void ULyraGameplayRpcRegistrationComponent::RegisterAlwaysOnHttpCallbacks()
{
	Super::RegisterAlwaysOnHttpCallbacks();	 // 调用父类实现
	const FExternalRpcArgumentDesc CommandDesc(TEXT("command"), TEXT("string"), TEXT("要告诉可执行文件运行的命令。")); // 定义命令参数描述

	RegisterHttpCallback(FName(TEXT("CheatCommand")), // 注册作弊命令回调
		FHttpPath("/core/cheatcommand"), // HTTP 路径
		EHttpServerRequestVerbs::VERB_POST, // HTTP 方法为 POST
		FHttpRequestHandler::CreateUObject(this, &ThisClass::HttpExecuteCheatCommand), // 请求处理函数
		true, // 是否始终启用
		TEXT("Cheats"), // 标签
		TEXT("raw"), // 响应类型
		{ CommandDesc }); // 参数描述列表
}

/**
 * 注册比赛中启用的 HTTP 回调
 */
void ULyraGameplayRpcRegistrationComponent::RegisterInMatchHttpCallbacks()
{
	RegisterHttpCallback(FName(TEXT("GetPlayerStatus")), // 注册获取玩家状态回调
		FHttpPath("/player/status"), // HTTP 路径
		EHttpServerRequestVerbs::VERB_GET, // HTTP 方法为 GET
		FHttpRequestHandler::CreateUObject(this, &ThisClass::HttpGetPlayerVitalsCommand), // 请求处理函数
		true); // 是否始终启用

	RegisterHttpCallback(FName(TEXT("PlayerFireOnce")), // 注册玩家射击一次回调
		FHttpPath("/player/status"), // HTTP 路径
		EHttpServerRequestVerbs::VERB_POST, // HTTP 方法为 POST
		FHttpRequestHandler::CreateUObject(this, &ThisClass::HttpFireOnceCommand), // 请求处理函数
		true); // 是否始终启用
	
}

/**
 * 注册前端启用的 HTTP 回调
 */
void ULyraGameplayRpcRegistrationComponent::RegisterFrontendHttpCallbacks()
{
    // 待办: 在此处添加匹配相关的 RPC
}

/**
 * 注销所有已注册的 HTTP 回调
 */
void ULyraGameplayRpcRegistrationComponent::DeregisterHttpCallbacks()
{
	Super::DeregisterHttpCallbacks(); // 调用父类实现
}

/**
 * 处理执行作弊命令的 HTTP 请求
 */
bool ULyraGameplayRpcRegistrationComponent::HttpExecuteCheatCommand(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete)
{
	TSharedPtr<FJsonObject> BodyObject = GetJsonObjectFromRequestBody(Request.Body); // 从请求体获取 JSON 对象

	if (!BodyObject.IsValid()) // 如果 JSON 对象无效
	{
		TUniquePtr<FHttpServerResponse>Response = CreateSimpleResponse(false, TEXT("无效的请求体对象")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}
	if (BodyObject->GetStringField(TEXT("command")).IsEmpty()) // 如果命令字段为空
	{
		TUniquePtr<FHttpServerResponse>Response = CreateSimpleResponse(false, TEXT("在 JSON 请求体中未找到命令")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}
	ALyraPlayerController* LPC = GetPlayerController(); // 获取玩家控制器
	if (!LPC) // 如果玩家控制器不存在
	{
		TUniquePtr<FHttpServerResponse>Response = CreateSimpleResponse(false, TEXT("未找到玩家控制器")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}
	FString CheatCommand = FString::Printf(TEXT("%s"), *BodyObject->GetStringField(TEXT("command"))); // 格式化作弊命令字符串
	LPC->ConsoleCommand(*CheatCommand, true); // 执行控制台命令

	TUniquePtr<FHttpServerResponse>Response = CreateSimpleResponse(true); // 创建成功响应
	OnComplete(MoveTemp(Response)); // 完成回调
	return true; // 返回 true 表示处理完成
}

/**
 * 处理触发一次射击的 HTTP 请求
 */
bool ULyraGameplayRpcRegistrationComponent::HttpFireOnceCommand(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete)
{
	ALyraPlayerController* LPC = GetPlayerController(); // 获取玩家控制器
	if (!LPC) // 如果玩家控制器不存在
	{
		TUniquePtr<FHttpServerResponse> Response = CreateSimpleResponse(false, TEXT("未找到玩家控制器")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}
	APawn* FortPlayerPawn = LPC->GetPawn(); // 获取玩家控制的 Pawn
	if (!FortPlayerPawn) // 如果 Pawn 不存在
	{
		TUniquePtr<FHttpServerResponse> Response = CreateSimpleResponse(false, TEXT("未找到玩家 Pawn")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}

	// 待办: 在此处实现射击一次的逻辑
	TUniquePtr<FHttpServerResponse> Response = CreateSimpleResponse(true); // 创建成功响应
	OnComplete(MoveTemp(Response)); // 完成回调
	return true; // 返回 true 表示处理完成
}

/**
 * 处理获取玩家状态（如生命值、物品栏）的 HTTP 请求
 */
bool ULyraGameplayRpcRegistrationComponent::HttpGetPlayerVitalsCommand(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete)
{
	ALyraPlayerController* LPC = GetPlayerController(); // 获取玩家控制器
	if (!LPC) // 如果玩家控制器不存在
	{
		TUniquePtr<FHttpServerResponse> Response = CreateSimpleResponse(false, TEXT("未找到玩家控制器")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}
	APawn* PlayerPawn = LPC->GetPawn(); // 获取玩家控制的 Pawn
	if (!PlayerPawn) // 如果 Pawn 不存在
	{
		TUniquePtr<FHttpServerResponse> Response = CreateSimpleResponse(false, TEXT("未找到玩家 Pawn")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}

	ALyraPlayerState* LyraPlayerState = LPC->GetLyraPlayerState(); // 获取 Lyra 玩家状态
	if (!LyraPlayerState) // 如果玩家状态不存在
	{
		TUniquePtr<FHttpServerResponse> Response = CreateSimpleResponse(false, TEXT("未找到玩家状态")); // 创建错误响应
		OnComplete(MoveTemp(Response)); // 完成回调
		return true; // 返回 true 表示处理完成
	}

	FString ResponseStr;  // 响应字符串
	TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&ResponseStr); // 创建 JSON 写入器
	TSharedPtr<FJsonObject> BodyObject = MakeShareable(new FJsonObject()); // 创建共享的 JSON 对象（未使用？）
	JsonWriter->WriteObjectStart(); // 开始写入 JSON 对象
	if (ULyraHealthComponent* HealthComponent = ULyraHealthComponent::FindHealthComponent(PlayerPawn)) // 查找健康组件
	{
		JsonWriter->WriteValue(TEXT("health"), FString::SanitizeFloat(HealthComponent->GetHealth())); // 写入生命值
	}
	if (ULyraInventoryManagerComponent* InventoryComponent = LPC->GetComponentByClass<ULyraInventoryManagerComponent>()) // 查找物品栏管理组件
	{
		JsonWriter->WriteArrayStart(TEXT("inventory")); // 开始写入物品栏数组
		for (ULyraInventoryItemInstance* ItemInstance : InventoryComponent->GetAllItems()) // 遍历所有物品实例
		{
			// 待办: 在此处转储任何相关的玩家信息。
		}
		JsonWriter->WriteArrayEnd(); // 结束物品栏数组
	}
	JsonWriter->WriteObjectEnd(); // 结束 JSON 对象
	JsonWriter->Close(); // 关闭 JSON 写入器
	TUniquePtr<FHttpServerResponse>Response = FHttpServerResponse::Create(ResponseStr, TEXT("application/json")); // 创建 JSON 响应
	OnComplete(MoveTemp(Response)); // 完成回调
	return true; // 返回 true 表示处理完成
}

#endif